package org.grayrabbit.cms.utils;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class IOUtil {
	private static final Logger log = LoggerFactory.getLogger(IOUtil.class);
	private static final int DEFAULT_BUFFER_SIZE = 4096;

	public static void shutdownReader(Reader input) {
		if (null == input) {
			return;
		}

		try {
			input.close();
		} catch (IOException ioe) {
		}
	}

	public static void shutdownWriter(Writer output) {
		if (null == output) {
			return;
		}

		try {
			output.close();
		} catch (IOException ioe) {
		}
	}

	public static void shutdownStream(OutputStream output) {
		if (null == output) {
			return;
		}

		try {
			output.close();
		} catch (IOException ioe) {
		}
	}

	public static void shutdownStream(InputStream input) {
		if (null == input) {
			return;
		}

		try {
			input.close();
		} catch (IOException ioe) {
		}
	}

	public static void copy(InputStream input, OutputStream output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	public static void copy(InputStream input, OutputStream output,
			int bufferSize) throws IOException {
		byte[] buffer = new byte[bufferSize];
		int n = 0;
		while (-1 != (n = input.read(buffer))) {
			output.write(buffer, 0, n);
		}
	}

	public static void copy(Reader input, Writer output) throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	public static void copy(Reader input, Writer output, int bufferSize)
			throws IOException {
		char[] buffer = new char[bufferSize];
		int n = 0;
		while (-1 != (n = input.read(buffer))) {
			output.write(buffer, 0, n);
		}
	}

	public static void copy(InputStream input, Writer output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	public static void copy(InputStream input, Writer output, int bufferSize)
			throws IOException {
		InputStreamReader in = new InputStreamReader(input);
		copy(in, output, bufferSize);
	}

	public static void copy(InputStream input, Writer output, String encoding)
			throws IOException {
		InputStreamReader in = new InputStreamReader(input, encoding);
		copy(in, output);
	}

	public static void copy(InputStream input, Writer output, String encoding,
			int bufferSize) throws IOException {
		InputStreamReader in = new InputStreamReader(input, encoding);
		copy(in, output, bufferSize);
	}

	public static String toString(InputStream input) throws IOException {
		return toString(input, DEFAULT_BUFFER_SIZE);
	}

	public static String toString(InputStream input, int bufferSize)
			throws IOException {
		StringWriter sw = new StringWriter();
		copy(input, sw, bufferSize);
		return sw.toString();
	}

	public static String toString(InputStream input, String encoding)
			throws IOException {
		return toString(input, encoding, DEFAULT_BUFFER_SIZE);
	}

	public static String toString(InputStream input, String encoding,
			int bufferSize) throws IOException {
		StringWriter sw = new StringWriter();
		copy(input, sw, encoding, bufferSize);
		return sw.toString();
	}

	public static byte[] toByteArray(InputStream input) throws IOException {
		return toByteArray(input, DEFAULT_BUFFER_SIZE);
	}

	public static byte[] toByteArray(InputStream input, int bufferSize)
			throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		copy(input, output, bufferSize);
		return output.toByteArray();
	}

	public static void copy(Reader input, OutputStream output)
			throws IOException {
		copy(input, output, 4096);
	}

	public static void copy(Reader input, OutputStream output, int bufferSize)
			throws IOException {
		OutputStreamWriter out = new OutputStreamWriter(output);
		copy(input, out, bufferSize);

		out.flush();
	}

	public static String toString(Reader input) throws IOException {
		return toString(input, DEFAULT_BUFFER_SIZE);
	}

	public static String toString(Reader input, int bufferSize)
			throws IOException {
		StringWriter sw = new StringWriter();
		copy(input, sw, bufferSize);
		return sw.toString();
	}

	public static byte[] toByteArray(Reader input) throws IOException {
		return toByteArray(input, 4096);
	}

	public static byte[] toByteArray(Reader input, int bufferSize)
			throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		copy(input, output, bufferSize);
		return output.toByteArray();
	}

	public static void copy(String input, OutputStream output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	public static void copy(String input, OutputStream output, int bufferSize)
			throws IOException {
		StringReader in = new StringReader(input);
		OutputStreamWriter out = new OutputStreamWriter(output);
		copy(in, out, bufferSize);

		out.flush();
	}

	public static void copy(String input, Writer output) throws IOException {
		output.write(input);
	}


	public static byte[] toByteArray(String input) throws IOException {
		return toByteArray(input, DEFAULT_BUFFER_SIZE);
	}

	public static byte[] toByteArray(String input, int bufferSize)
			throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		copy(input, output, bufferSize);
		return output.toByteArray();
	}

	public static void copy(byte[] input, Writer output) throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	public static void copy(byte[] input, Writer output, int bufferSize)
			throws IOException {
		ByteArrayInputStream in = new ByteArrayInputStream(input);
		copy(in, output, bufferSize);
	}

	public static void copy(byte[] input, Writer output, String encoding)
			throws IOException {
		ByteArrayInputStream in = new ByteArrayInputStream(input);
		copy(in, output, encoding);
	}

	public static void copy(byte[] input, Writer output, String encoding,
			int bufferSize) throws IOException {
		ByteArrayInputStream in = new ByteArrayInputStream(input);
		copy(in, output, encoding, bufferSize);
	}

	public static String toString(byte[] input) throws IOException {
		return toString(input, DEFAULT_BUFFER_SIZE);
	}

	public static String toString(byte[] input, int bufferSize)
			throws IOException {
		StringWriter sw = new StringWriter();
		copy(input, sw, bufferSize);
		return sw.toString();
	}

	public static String toString(byte[] input, String encoding)
			throws IOException {
		return toString(input, encoding, 4096);
	}

	public static String toString(byte[] input, String encoding, int bufferSize)
			throws IOException {
		StringWriter sw = new StringWriter();
		copy(input, sw, encoding, bufferSize);
		return sw.toString();
	}

	public static void copy(byte[] input, OutputStream output)
			throws IOException {
		copy(input, output, 4096);
	}

	public static void copy(byte[] input, OutputStream output, int bufferSize)
			throws IOException {
		output.write(input);
	}

	public static boolean contentEquals(InputStream input1, InputStream input2)
			throws IOException {
		InputStream bufferedInput1 = new BufferedInputStream(input1);
		InputStream bufferedInput2 = new BufferedInputStream(input2);

		int ch = bufferedInput1.read();
		while (-1 != ch) {
			int ch2 = bufferedInput2.read();
			if (ch != ch2) {
				return false;
			}
			ch = bufferedInput1.read();
		}

		int ch2 = bufferedInput2.read();

		return -1 == ch2;
	}

	public static byte[] getLeadingBytes(InputStream is, int numBytes)
			throws IOException {
		byte[] bytes = new byte[numBytes];
		int i = 0;
		while (true) {
			int n = is.read(bytes, i, numBytes - i);
			if (n == -1) {
				return ArrayUtils.subarray(bytes, 0, i);
			}

			i += n;
			if (i >= numBytes) {
				return bytes;
			}
		}
	}

	public static void copy(File src, File dst) throws IOException {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream(src);
			fos = new FileOutputStream(dst);
			copy(fis, fos);
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					log.error(
							"Error closing input stream from file "
									+ src.getPath(), e);
				}
			}
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					log.error(
							"Error closing output stream to file "
									+ dst.getPath(), e);
				}
			}
		}
	}
}
